home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / haeberli / libgutil / path.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  10KB  |  549 lines

  1. /*
  2.  * Copyright 1991, 1992, 1993, 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. /*
  18.  *    path - 
  19.  *        General functions to support creation of PostScript
  20.  *    stroked, filled, and beveled paths.
  21.  *
  22.  *                Paul Haeberli - 1990
  23.  */
  24. #include "stdio.h"
  25. #include "gl.h"
  26. #include "sgiobj.h"
  27. #include "vect.h"
  28. #include "path.h"
  29.  
  30. /* #define MAKETMESHES */
  31. /*
  32.  *    function prototypes
  33.  *
  34.  *
  35.  */
  36. extern sgiobj *getfaces();
  37. extern sgiobj *follow();
  38.  
  39. static void checkpath();
  40. static void addtopath(path *p, pathseg *ps);
  41. static addline(path *p, float x1, float y1, float x2, float y2);
  42. static addcurve(path *p, float x1, float y1, float x2, float y2,
  43.              float x3, float y3, float x4, float y4);
  44. static int nfloats(path *p);
  45. static void flattenpath(path *p);
  46. static bezadapt(float x0,float y0,float x1,float y1,
  47.       float x2,float y2,float x3,float y3,float beztol,path *p, int startb);
  48. static void entershape(path *p, int dopath);
  49.  
  50. /*
  51.  *    global variables
  52.  *
  53.  *
  54.  */
  55. static float curflatness = -1.0;
  56. static float curx, cury;
  57. static float startx, starty;
  58. static path *curpath;
  59. static path *bevpath;
  60. static int nsegs;
  61.  
  62. /*
  63.  *    internal functions 
  64.  *
  65.  *
  66.  */
  67. static void checkpath()
  68. {
  69.     if(!curpath) {
  70.     curpath = (path *)mymalloc(sizeof(path));
  71.     curpath->type = TYPE_BUILD;
  72.     curpath->ncurves = 0;
  73.     curpath->head=0;
  74.     curpath->tail=0;
  75.     curpath->data=0;
  76.     nsegs = 0;
  77.     }
  78. }
  79.  
  80. static void addtopath(path *p, pathseg *ps)
  81. {
  82.     ps->next = 0;
  83.     if(p->tail) {
  84.     p->tail->next = ps;
  85.     p->tail = ps;
  86.     } else 
  87.     p->head = p->tail = ps;
  88. }
  89.  
  90. static addline(path *p, float x1, float y1, float x2, float y2)
  91. {
  92.     pathline *pl;
  93.  
  94.     pl = (pathline *)mymalloc(sizeof(pathline));
  95.     pl->x1 = x1;
  96.     pl->x2 = x2;
  97.     pl->y1 = y1;
  98.     pl->y2 = y2;
  99.     pl->dx1 = x2-x1;
  100.     pl->dy1 = y2-y1;
  101.     pl->dx2 = x2-x1;
  102.     pl->dy2 = y2-y1;
  103.     if(nsegs == 0) 
  104.     pl->attr = SEG_LINE|START_BIT;
  105.     else
  106.     pl->attr = SEG_LINE;
  107.     addtopath(curpath,(pathseg *)pl);
  108.     nsegs++;
  109. }
  110.  
  111. static addcurve(path *p, float x1, float y1, float x2, float y2,
  112.              float x3, float y3, float x4, float y4)
  113. {
  114.     pathcurve *pc;
  115.  
  116.     curpath->ncurves++;
  117.     pc = (pathcurve *)mymalloc(sizeof(pathcurve));
  118.     pc->x1 = x1;
  119.     pc->x2 = x2;
  120.     pc->x3 = x3;
  121.     pc->x4 = x4;
  122.     pc->y1 = y1;
  123.     pc->y2 = y2;
  124.     pc->y3 = y3;
  125.     pc->y4 = y4;
  126.     if(nsegs == 0) 
  127.     pc->attr = SEG_CURVE|START_BIT;
  128.     else
  129.     pc->attr = SEG_CURVE;
  130.     addtopath(curpath,(pathseg *)pc);
  131.     nsegs++;
  132. }
  133.  
  134. static int nfloats(path *p)
  135. {
  136.     int nf;
  137.     pathseg *ps;
  138.     path *flatp, fp;
  139.  
  140.     nf = 0;
  141.     ps = curpath->head;
  142.     while(ps) {
  143.     nf += 2;
  144.     if(ps->attr & START_BIT) {
  145.         nf++;
  146.         nf += 2;
  147.     }
  148.         ps = ps->next;
  149.     }
  150.     nf++;
  151.     return nf;
  152. }
  153.  
  154. static void flattenpath(path *p)
  155. {
  156.     pathseg *ps, *txen, *pstart;
  157.     pathcurve *pc;
  158.     int startb;
  159.  
  160.     if(curpath->ncurves == 0) 
  161.     return;
  162.     if(curflatness<0.0) {
  163.     fprintf(stderr,"must call setflat(flatness) before using curves\n");
  164.     exit(1);
  165.     }
  166.     pstart = p->head;
  167.     p->head = p->tail = 0;
  168.  
  169.     ps = pstart;
  170.     while(ps) {
  171.     txen = ps->next;
  172.     ps = txen;
  173.     }
  174.     ps = pstart;
  175.     while(ps) {
  176.     txen = ps->next;
  177.  
  178.     if((ps->attr&SEG_MASK) == SEG_LINE) {
  179.         addtopath(p,ps);
  180.     } else {
  181.         startb = ps->attr & START_BIT;
  182.         pc = (pathcurve *)ps;
  183.         bezadapt(pc->x1,pc->y1,pc->x2,pc->y2,
  184.             pc->x3,pc->y3,pc->x4,pc->y4,curflatness,p,startb);
  185.         free(ps);
  186.     }
  187.     ps = txen;
  188.     }
  189.     p->ncurves = 0;
  190. }
  191.  
  192. static bezadapt(float x0,float y0,float x1,float y1,
  193.       float x2,float y2,float x3,float y3,float beztol,path *p, int startb)
  194. {
  195.     float ax0,ay0,ax1,ay1,ax2,ay2,ax3,ay3;
  196.     float bx0,by0,bx1,by1,bx2,by2,bx3,by3;
  197.     float midx, midy;
  198.     float linx, liny, dx, dy, mag;
  199.     pathline *pl;
  200.    
  201.     midx = (x0+3*x1+3*x2+x3)/8.0;
  202.     midy = (y0+3*y1+3*y2+y3)/8.0;
  203.     linx = (x0+x3)/2.0;
  204.     liny = (y0+y3)/2.0;
  205.     dx = midx-linx;
  206.     dy = midy-liny;
  207.     mag = dx*dx+dy*dy;
  208.     if(mag<(beztol*beztol)) {
  209.     /* drawline(x0,y0,x3,y3,x1-x0,y1-y0,x3-x2,y3-y2); */
  210.     pl = (pathline *)mymalloc(sizeof(pathline));
  211.     pl->x1 = x0;
  212.     pl->y1 = y0;
  213.     pl->x2 = x3;
  214.     pl->y2 = y3;
  215.     pl->dx1 = x1-x0;
  216.     pl->dy1 = y1-y0;
  217.     pl->dx2 = x3-x2;
  218.     pl->dy2 = y3-y2;
  219.     if(startb) {
  220.         pl->attr = SEG_LINE|START_BIT;
  221.      } else
  222.         pl->attr = SEG_LINE;
  223.     addtopath(p,(pathseg *)pl);
  224.     } else {
  225.     ax0 = x0;
  226.     ay0 = y0;
  227.     ax1 = (x0+x1)/2.0;
  228.     ay1 = (y0+y1)/2.0;
  229.     ax2 = (x0+2.0*x1+x2)/4.0;
  230.     ay2 = (y0+2.0*y1+y2)/4.0;
  231.     ax3 = midx;
  232.     ay3 = midy;
  233.     bezadapt(ax0,ay0,ax1,ay1,ax2,ay2,ax3,ay3,beztol,p,startb);
  234.  
  235.     bx0 = midx;
  236.     by0 = midy;
  237.     bx1 = (x1+2.0*x2+x3)/4.0;
  238.     by1 = (y1+2.0*y2+y3)/4.0;
  239.     bx2 = (x2+x3)/2.0;
  240.     by2 = (y2+y3)/2.0;
  241.     bx3 = x3;
  242.     by3 = y3;
  243.     bezadapt(bx0,by0,bx1,by1,bx2,by2,bx3,by3,beztol,p,0);
  244.     }
  245. }
  246.  
  247. static void entershape(path *p, int dopath)
  248. {
  249.     vect s, l, c;
  250.     vect ds, dl, dc;
  251.     int nsides;
  252.     pathline *pl;
  253.  
  254.     pl = (pathline *)p->head;
  255.     if(dopath) 
  256.     pathbegin();
  257.     else
  258.     tempbegin();
  259.     nsides = 0;
  260.     while(pl) {
  261.     if(pl->attr & START_BIT) {
  262.         if(nsides>0 && dopath) {
  263.         if(c.x != s.x || c.y != s.y) 
  264.             mypathsegment(&c,&dc,&s,&ds);
  265.         pathclose();
  266.         }
  267.         nsides = 0;
  268.     }
  269.     l.x = pl->x1;
  270.     l.y = pl->y1;
  271.     dl.x = pl->dx1;
  272.     dl.y = pl->dy1;
  273.     c.x = pl->x2;
  274.     c.y = pl->y2;
  275.     dc.x = pl->dx2;
  276.     dc.y = pl->dy2;
  277.     if(nsides == 0) {
  278.         s = l;
  279.         ds = dl;
  280.     }
  281.     if(dopath) 
  282.         mypathsegment(&l,&dl,&c,&dc);
  283.      else
  284.         tempsegment(&l,&dl,&c,&dc);
  285.     nsides++;
  286.     pl = (pathline *)pl->next;
  287.     }
  288.     if(nsides>0 && dopath) {
  289.     if(c.x != s.x || c.y != s.y) 
  290.         mypathsegment(&c,&dc,&s,&ds);
  291.     
  292.     }
  293.     if(dopath) 
  294.     pathclose();
  295.     else
  296.     tempclose();
  297. }
  298.  
  299. mypathsegment(v1,dv1,v2,dv2)
  300. vect *v1,*dv1,*v2,*dv2;
  301. {
  302.     pathsegment(v1,dv1,v2,dv2);
  303. }
  304.  
  305. /*
  306.  *    set global properties
  307.  *
  308.  *
  309.  */
  310. void setflat(float flat)
  311. {
  312.     curflatness = flat;
  313. }
  314.  
  315. void setbevel()
  316. {
  317.     checkpath();
  318.     freepath(bevpath);
  319.     flattenpath(curpath);
  320.     bevpath = curpath;
  321.     curpath = 0;
  322. }
  323.  
  324. /*
  325.  *    build a path structure 
  326.  *
  327.  *
  328.  */
  329. void newpath()
  330. {
  331.     checkpath();
  332. }
  333.  
  334. void closepath()
  335. {
  336.     if(curpath && curpath->tail) 
  337.     lineto(startx,starty);
  338.     nsegs = 0;
  339. }
  340.  
  341. void moveto(float x, float y)
  342. {
  343.     startx = curx = x;
  344.     starty = cury = y;
  345.     nsegs = 0;
  346. }
  347.  
  348. void lineto(float x, float y)
  349. {
  350.     checkpath();
  351.     if(x != curx || y != cury) {
  352.     addline(curpath,curx,cury,x,y);
  353.     curx = x;
  354.     cury = y;
  355.     }
  356. }
  357.  
  358. void curveto(float x1, float y1, float x2, float y2, float x3, float y3)
  359. {
  360.     checkpath();
  361.     addcurve(curpath,curx,cury,x1,y1,x2,y2,x3,y3);
  362.     curx = x3;
  363.     cury = y3;
  364. }
  365.  
  366. /*
  367.  *    free a path
  368.  *
  369.  */
  370. void freepath(path *p)
  371. {
  372.     pathseg *ps, *next;;
  373.  
  374.     if(!p)
  375.     return;
  376.     switch(p->type) {
  377.     case TYPE_BUILD:
  378.         ps = p->head;
  379.         while(ps) {
  380.         next = ps->next;
  381.         free(ps);
  382.         ps = next;
  383.         }
  384.         free(p);
  385.         break;
  386.     case TYPE_STROKE:
  387.         free(p->data);
  388.         free(p);
  389.         break;
  390.     case TYPE_FILL:
  391.     case TYPE_BEVELED:
  392.         freesgiobj(p->data);
  393.         free(p);
  394.         break;
  395.     }
  396. }
  397.  
  398. /*
  399.  *    create a path using current bevel and current flatness.
  400.  *
  401.  *
  402.  */
  403. path *stroke()
  404. {
  405.     pathline *pl;
  406.     path *p;
  407.     int nf, count;
  408.     float *fptr, *cptr;
  409.  
  410.     checkpath();
  411.     flattenpath(curpath);
  412.     nf = nfloats(curpath);
  413.     p = (path *)mymalloc(sizeof(path));
  414.     p->type = TYPE_STROKE;
  415.     p->data=(char *)mymalloc(nf*sizeof(float));
  416.     fptr = (float*)p->data;
  417.     pl = (pathline *)curpath->head;
  418.     cptr = 0;
  419.     count = 0;
  420.     while(pl) {
  421.     nf += 2;
  422.     if(pl->attr & START_BIT) {
  423.         if(cptr) {
  424.         *cptr = count;
  425.         count = 0;
  426.         }
  427.         cptr = fptr;
  428.         fptr++;
  429.         *fptr++ = pl->x1;
  430.         *fptr++ = pl->y1;
  431.         count++;
  432.     }
  433.     *fptr++ = pl->x2;
  434.     *fptr++ = pl->y2;
  435.     count++;
  436.         pl = (pathline *)pl->next;
  437.     }
  438.     if(cptr) 
  439.     *cptr = count;
  440.     *fptr++ = 0;
  441.     freepath(curpath);
  442.     curpath = 0;
  443.     return p;
  444. }
  445.  
  446. path *fill()
  447. {
  448.     float x, y;
  449.     vect p0, p1, s, l, c;
  450.     int nsides;
  451.     pathline *pl;
  452.     path *p;
  453.     sgiobj *obj, *tobj;
  454.  
  455.     checkpath();
  456.     flattenpath(curpath);
  457.  
  458.     tempbegin();
  459.     p0.x = 1.0;
  460.     p0.y = 0.0;
  461.     p1.x = 0.0;
  462.     p1.y = 0.0;
  463.     tempsegment(&p0,0,&p1,0);
  464.  
  465.     entershape(curpath,1);
  466.     obj = getfaces();
  467.  
  468.     p = (path *)mymalloc(sizeof(path));
  469.     p->type = TYPE_FILL;
  470.     p->data=(char *)obj;
  471.     freepath(curpath);
  472.     curpath = 0;
  473.     return p;
  474. }
  475.  
  476. path *bevel3d()
  477. {
  478.     vect p0, p1;
  479.     pathline *pl;
  480.     path *p;
  481.     sgiobj *obj, *fobj, *bobj, *tobj;
  482.  
  483.     checkpath();
  484.     flattenpath(curpath);
  485.  
  486.     if(bevpath) {
  487.     entershape(bevpath,0);
  488.  
  489.     entershape(curpath,1);
  490.  
  491.     fobj = getfaces();
  492.     bobj = follow();
  493.     if(fobj && bobj) {
  494.         obj = catsgiobj(fobj,bobj);
  495.         freesgiobj(fobj);
  496.         freesgiobj(bobj);
  497.     } else if(fobj) 
  498.        obj = fobj;
  499.     else if(bobj)
  500.        obj = bobj;
  501.     else {
  502.         printf("no objects from getfaces and follow\n");
  503.         exit(1);
  504.     }
  505.  
  506.     p = (path *)mymalloc(sizeof(path));
  507.     p->type = TYPE_BEVELED;
  508.     p->data=(char *)obj;
  509.     }
  510.     freepath(curpath);
  511.     curpath = 0;
  512.     return p;
  513. }
  514.  
  515. /*
  516.  *    actually draw a path
  517.  *
  518.  *
  519.  */
  520. void drawpath(path *p)
  521. {
  522.     float *fptr;
  523.     int n;
  524.  
  525.     switch(p->type) {
  526.     case TYPE_STROKE:
  527.         fptr = (float *)p->data;
  528.         n = *fptr++;
  529.         while(n>0) {
  530.         bgnline();
  531.         while(n--) {
  532.             v2f(fptr);
  533.             fptr += 2;
  534.         }
  535.         endline();
  536.         n = *fptr++;
  537.         }
  538.         break;
  539.     case TYPE_FILL:
  540.         drawsgiobj(p->data,DRAW_POINTS);
  541.         break;
  542.     case TYPE_BEVELED:
  543.         drawsgiobj(p->data,DRAW_POINTS|DRAW_NORMALS);
  544.         break;
  545.         
  546.     }
  547. }
  548.  
  549.